#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <limits.h>
#include <iconv.h>

#include <string>
#include <vector>

#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <memory.h>
#include <time.h>
#include <sys/time.h>
#include <dirent.h>

#include "cpputils.h"
#include <sstream>
#include <iomanip>
using namespace std;

string to_lower(const string& str)
{
    if (str.empty())
        return str;

    unsigned i = 0;
    string tmp(str.length(),'\0');
    while ( i < str.length())
    {
        tmp[i] = char(tolower(str[i]));
        ++i;
    }
    return tmp;
}

string to_upper(const string& str)
{
    if (str.empty())
        return str;

    unsigned i = 0;
    string tmp(str.length(),'\0');
    while ( i < str.length())
    {
        tmp[i] = char(toupper(str[i]));
        ++i;
    }
    return tmp;
}

bool IsFastCGI()
{
    int ret = getpeername(0, NULL, NULL);
    if(ret==-1 && errno==ENOTCONN)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int stringSplit(const string& str, const string& sep, vector<string> &vec )
{
    if (str.empty() || sep.empty())
        return 0;

    size_t posBegin = 0;
    size_t posEnd = str.find(sep,posBegin);
    while(posEnd != string::npos)
    {
        vec.push_back(str.substr(posBegin,posEnd-posBegin));
        posBegin = posEnd + sep.length();
        posEnd = str.find(sep,posBegin);
    }
    if (posBegin < str.length() )
        vec.push_back(str.substr(posBegin));
    else if (posBegin >= str.length() )
        vec.push_back("");

    return vec.size();
}

void stringSplit(const string& str,
        const string& fstsep,
        const string& secsep,
        map<string,string>& cpqx)
{
    // 204001:1,204002:2
    vector<string> vfst;
    stringSplit(str,fstsep,vfst);

    vector<string>::iterator it;
    vector<string> vsec;
    for (it = vfst.begin(); it != vfst.end(); ++it)
    {
        vsec.clear();
        stringSplit(*it,secsep,vsec);
        if (vsec.size() != 2)
            continue;

        cpqx[vsec[0]] = vsec[1];
    }
}

string& trim(string& str, const string& trimStr /* = " \r\n\t" */)
{
    size_t len = str.length();
    size_t begin = 0,end=len;

    while(begin < len)
    {
        if (trimStr.find(str[begin]) == string::npos)
            break;
        ++begin;
    }
    while(end - 1 > 0 && end - 1 > begin)
    {
        if (trimStr.find(str[end - 1]) == string::npos)
            break;
        --end;
    }

    str = str.substr(begin,end - begin);
    return str;
}

/* from,to: 通过 iconv --list来查询 */
void charset_conv(const string& input,string& output,const string& from,const string& to)
{
    if (input.empty())
        return;

    string tmpInput(input);
    output.clear();
    size_t inLen = tmpInput.length(), outLen = inLen * 4;
    size_t origInLen = inLen, origOutLen = outLen;
    char* pIn = const_cast<char*>(tmpInput.c_str());
    char* pOut = new char[outLen];
    memset(pOut,0,outLen);
    iconv_t dc = iconv_open(to.c_str(),from.c_str());
    /// 转换前
    /// inLen,outLen 必须初始化，分别代表：可从input中读取的最大字节数及 pOut的容量
    /// 转换后
    /// inLen: pIn 剩余字节数
    /// outLen: pOut 中实际有效的字节数
    iconv(dc,&pIn,&inLen,&pOut,&outLen);
    /// 位置有变动
    pIn = pIn - (origInLen - inLen);
    pOut = pOut - (origOutLen - outLen);
    output = string(pOut);
    iconv_close(dc);
    delete[] pOut;
}

string GetTime(const string& fmt)
{
    time_t tmt = time(NULL);
    struct tm *pTime = localtime(&tmt);
    char   timeBuf[64]={0};
    strftime(timeBuf,sizeof(timeBuf),fmt.c_str(),pTime);
    return string(timeBuf);
}

string GetTimestamp()
{
    struct timeval tv; 
    gettimeofday(&tv,NULL);

    string tm = GetTime("%Y-%m-%d %H:%M:%S");
    string ms = int2a(tv.tv_usec/1000);
    // 前补0
    if ( ms.size() < 3 ) 
    {   
        string pref(3 - ms.size(),'0');
        ms = pref + ms; 
    }   
    tm += "." + ms; 

    return tm; 
}

void EnumDirFiles(const string& dir, vector<string>& vFiles, bool includeDir)
{
    if (dir.empty())
        return;

    string path = dir;;
    if ( path.find_last_of("/") != path.length() - 1)
        path += "/";

    struct stat fileStat;
    DIR* pDir = opendir(path.c_str());
    if (!pDir) return;

    struct dirent* pDirEnt = NULL;
    bool bpushdir = false;
    while ( (pDirEnt = readdir(pDir)) != NULL )
    {
        if (strcmp(pDirEnt->d_name,".") == 0 || strcmp(pDirEnt->d_name,"..") == 0)
            continue;

        if ( includeDir && !bpushdir)
        {
            vFiles.push_back(path);
            bpushdir = true;
        }
        
        string tmpDir = path + pDirEnt->d_name;
        if (stat(tmpDir.c_str(),&fileStat) != 0)
            continue;
        
        if ((fileStat.st_mode & S_IFDIR) == S_IFDIR)
        {
            
            EnumDirFiles(tmpDir,vFiles,includeDir);
            continue;
        }

        vFiles.push_back(tmpDir);
    }

    if (pDir)
        closedir(pDir);
}

void EnumProcPids(map<string,vector<int> >& pids)
{
    string path("/proc/");
    struct stat fileStat;
    DIR* pDir = opendir(path.c_str());
    if (!pDir) return;

    struct dirent* pDirEnt = NULL;
    while ( (pDirEnt = readdir(pDir)) != NULL )
    {
        if (strcmp(pDirEnt->d_name,".") == 0 || strcmp(pDirEnt->d_name,"..") == 0)
            continue;

        string tmpDir = path +  pDirEnt->d_name;
        if (stat(tmpDir.c_str(),&fileStat) != 0)
            continue;
        
        if ((fileStat.st_mode & S_IFDIR) == S_IFDIR)
        {
            int pid = atoi ( pDirEnt->d_name );
            if ( pid > 0 )
            {
                string filename = tmpDir + "/exe";
                char abspath[PATH_MAX] = {0};
                int pathlen = readlink(filename.c_str(),abspath,PATH_MAX);
                if ( pathlen > 0)
                    pids[abspath].push_back(pid);
            }
        }
    }

    if (pDir)
        closedir(pDir);

}

int beDaemon()
{
	pid_t pid;
	if ((pid = fork()) < 0)
		return -1;
	else if (pid != 0)		/// 父进程退出
		exit(0);
	
	/// 子进程创建一个新的会话，并成为会话组长
	setsid();
	umask(0);
	
	// attach stdin, stdout, stderr to /dev/null
	// instead of just closing them. This avoids
	// issues with third party/legacy code writing
	// stuff to stdout/stderr.
	FILE* fin  = freopen("/dev/null", "r+", stdin);
	if (!fin) return -1;
	FILE* fout = freopen("/dev/null", "r+", stdout);
	if (!fout) return -1;
	FILE* ferr = freopen("/dev/null", "r+", stderr);
	if (!ferr) return -1;

    return 0;
}

















